﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ReadeAssetManager
{
    public partial class ucSearchSchedule : UserControl, ISearchControl
    {
        AMSServiceRef.User _user;

        private const string DATE_IS = "Date Is";
        private const string DATE_BEG = "Date Beginning";
        private const string DATE_END = "Date Ending";
        private const string DATE_BET = "Date Between";
        private const string DATE_ANY = "Any Date";

        private const string RECUR_NONE = "Not Selected";
        private const string RECUR_DAILY = "Daily";
        private const string RECUR_WKLY = "Weekly";
        private const string RECUR_MNTH = "Monthly";
        private const string RECUR_ANNUAL = "Annually";

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="CurrentUser">[AMSServiceRef.User] The current application user.</param>
        public ucSearchSchedule(AMSServiceRef.User CurrentUser)
        {
            InitializeComponent();
            _user = CurrentUser;
            PopulateRecurranceOptions();
            LoadDateSearchOptions();
        }

        /// <summary>
        /// BuildAssetList
        /// Creates and returns a List of AMSServiceRef.Asset objects matching the search
        /// criteria.  This method is called indirectly from frmMain via a delegate in the
        /// ucSearch control.
        /// </summary>
        /// <returns>[List<AMSServiceRef.Asset>] List of assets matching the search criteria.</returns>
        public List<AMSServiceRef.Asset> BuildAssetList()
        {
            List<AMSServiceRef.Asset> assets = new List<AMSServiceRef.Asset>();

            if (_user != null)
            {
                foreach (AMSServiceRef.Asset asset in _user.Assets)
                {
                    if (IsAssetMatch(asset))
                        assets.Add(asset);
                }
            }

            return assets;
        }

        /// <summary>
        /// IsAssetMatch
        /// Determines whether the given asset matches the search parameters.
        /// </summary>
        /// <param name="CurrentAsset">[AMSServiceRef.Asset] The asset being checked.</param>
        /// <returns>[bool] True if this asset fits the search parameters, otherwise false.</returns>
        private bool IsAssetMatch(AMSServiceRef.Asset CurrentAsset)
        {
            bool isMatch = false;

            // No search options were selected
            if ((txtTitle.Text.Length + txtComments.Text.Length == 0) &&
                cmbRecur.Text == RECUR_NONE && !dtpFrom.Enabled && !dtpTo.Enabled)
                return true;

            foreach (AMSServiceRef.ScheduleData s in CurrentAsset.Schedules)
            {
                isMatch = true;

                // Title
                if (txtTitle.Text.Length > 0 && !s.Title.Contains(txtTitle.Text))
                    continue;

                // Service Number
                if (cmbRecur.SelectedText != RECUR_NONE && s.Recurrance != ((ComboboxItem)cmbRecur.SelectedItem).Value)
                    continue;

                // Comments
                if (txtComments.Text.Length > 0 && !s.Comments.Contains(txtComments.Text))
                    continue;

                // Date From/To
                if (dtpFrom.Enabled && dtpTo.Enabled)
                    isMatch = IsValidDate(dtpFrom, cmbDate, s.DateDue, true) &&
                              IsValidDate(dtpTo, cmbDate, s.DateDue, false);

                else if (dtpFrom.Enabled)
                    isMatch = IsValidDate(dtpFrom, cmbDate, s.DateDue, true);

                else if (dtpTo.Enabled)
                    isMatch = IsValidDate(dtpTo, cmbDate, s.DateDue, false);

                if (isMatch)
                    return true;
            }

            return false;
        }

        /// <summary>
        /// PopulateRecurranceOptions
        /// Loads the recurrance options and sets the default value.
        /// </summary>
        private void PopulateRecurranceOptions()
        {
            cmbRecur.Items.Clear();
            cmbRecur.Items.Add(new ComboboxItem(RECUR_NONE, 0));
            cmbRecur.Items.Add(new ComboboxItem(RECUR_DAILY, 1));
            cmbRecur.Items.Add(new ComboboxItem(RECUR_WKLY, 7));
            cmbRecur.Items.Add(new ComboboxItem(RECUR_MNTH, 30));
            cmbRecur.Items.Add(new ComboboxItem(RECUR_ANNUAL, 365));
            cmbRecur.Text = RECUR_NONE;
        }

        /// <summary>
        /// LoadDateSearchOptions
        /// Fills the cmbStartDate and cmbEndDate controls with the default values.
        /// </summary>
        private void LoadDateSearchOptions()
        {
            cmbDate.Items.Clear();
            cmbDate.Items.Add(DATE_IS);
            cmbDate.Items.Add(DATE_BEG);
            cmbDate.Items.Add(DATE_END);
            cmbDate.Items.Add(DATE_BET);
            cmbDate.Items.Add(DATE_ANY);
            cmbDate.Text = DATE_ANY;
        }

        /// <summary>
        /// cmbStartDate_TextChanged
        /// Enables/disables the appropriate date fields as the date search options are changed.
        /// </summary>
        /// <param name="sender">[object] The cmbStartDate control.</param>
        /// <param name="e">[EventArgs] The standard event arguments for a TextChanged event.</param>
        private void cmbDate_TextChanged(object sender, EventArgs e)
        {
            switch (cmbDate.Text)
            {
                case DATE_IS:
                    dtpFrom.Enabled = true;
                    dtpTo.Enabled = false;
                    break;
                case DATE_BEG:
                    dtpFrom.Enabled = true;
                    dtpTo.Enabled = false;
                    break;
                case DATE_END:
                    dtpFrom.Enabled = false;
                    dtpTo.Enabled = true;
                    break;
                case DATE_BET:
                    dtpFrom.Enabled = true;
                    dtpTo.Enabled = true;
                    break;
                case DATE_ANY:
                    dtpFrom.Enabled = false;
                    dtpTo.Enabled = false;
                    break;
                default:
                    dtpFrom.Enabled = false;
                    dtpTo.Enabled = false;
                    break;
            }
        }

        /// <summary>
        /// IsValidDate
        /// Determines whether the date given in DateToValidate meets the criteria given
        /// by the value in the Picker control and the selected option in the DateOption
        /// control.
        /// </summary>
        /// <param name="Picker">[DateTimePicker] The control containing the criteria value.</param>
        /// <param name="DateOption">[ComboBox] The control indicating how and whether the date should be read.</param>
        /// <param name="DateToValidate">[DateTime] The AMSServiceRef.Asset date being checked.</param>
        /// <param name="FromDate">[bool] True if checking the from date field, otherwise false.  Required for Date Between.</param>
        /// <returns>[bool] True if the DateToValidate meets the criteria, otherwise false.</returns>
        private bool IsValidDate(DateTimePicker Picker, ComboBox DateOption, DateTime DateToValidate, bool FromDate)
        {
            switch (DateOption.Text)
            {
                case DATE_IS:
                    if (FromDate)
                        return (DateToValidate == Picker.Value);
                    break;
                case DATE_BEG:
                    if (FromDate)
                        return (DateToValidate >= Picker.Value);
                    break;
                case DATE_END:
                    if (!FromDate)
                        return (DateToValidate <= Picker.Value);
                    break;
                case DATE_BET:
                    if (FromDate)
                        return (DateToValidate >= Picker.Value);
                    else
                        return (DateToValidate <= Picker.Value);
                    break;
                case DATE_ANY:
                    return true;
                    break;
                default:
                    // An unexpected option was selected.
                    return false;
                    break;
            }
            return false;
        }

        /// <summary>
        /// ComboboxItem
        /// A lightweight class to represent a combobox item.
        /// </summary>
        public class ComboboxItem
        {
            public ComboboxItem(string NewText, int NewValue)
            {
                Text = NewText;
                Value = NewValue;
            }
            public string Text { get; set; }
            public int Value { get; set; }

            public override string ToString()
            {
                return Text;
            }
        };
    }
}
